package com.tinem.platform.web.auth.config;

import cn.hutool.core.util.StrUtil;
import com.tinem.platform.module.starter.jpa.repository.oauth2.UserSessionTokenRepository;
import com.tinem.platform.web.auth.server.client.RedisAuthorizationCodeServices;
import com.tinem.platform.web.auth.server.client.token.PlatformSaveTokenEnhancer;
import com.tinem.platform.web.auth.server.client.token.PlatformTokenEnhancer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

import javax.annotation.Resource;
import java.util.Arrays;

/**
 * @author fengzhihao
 * @version v1
 * @program: platform
 * @className TokenService
 * @description TODO
 * @site 
 * @company 
 * @create 2020-07-01 18:34
 */
@Configuration
public class TokenConfigurer {
    @Resource
    TokenStore tokenStore;

    @Resource
    ClientDetailsService clientDetailsService;

    @Resource
    TokenEnhancerChain tokenEnhancerChain;

    /**
     * 通过公私钥对生成令牌。
     * @return
     */
    @Bean
    public JwtAccessTokenConverter accessTokenConverter(@Autowired JwtConfig jwtConfig) {
        JwtAccessTokenConverter jwtAccessTokenConverter = new JwtAccessTokenConverter();
        jwtAccessTokenConverter.setSigner(new RsaSigner(jwtConfig.getPv()));
        jwtAccessTokenConverter.setVerifier(new RsaVerifier(jwtConfig.getPu()));
        jwtAccessTokenConverter.setVerifierKey(StrUtil.format("-----BEGIN PUBLIC KEY-----\n{}\n-----END PUBLIC KEY-----", jwtConfig.getVerifierKey()));
        return jwtAccessTokenConverter;
    }

    /**
     * 令牌存储方式采用jwt方式
     * @param jwtAccessTokenConverter
     * @return
     */
    @Bean
    public TokenStore tokenStore(@Autowired JwtAccessTokenConverter jwtAccessTokenConverter) {
        return new JwtTokenStore(jwtAccessTokenConverter);
    }

    /**
     * 令牌增强类
     * @param jwtAccessTokenConverter
     * @return
     */
    @Bean
    public TokenEnhancerChain TokenEnhancerChain(
            @Autowired JwtAccessTokenConverter jwtAccessTokenConverter
            ,@Autowired UserSessionTokenRepository userSessionTokenRepository){
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(
                new PlatformTokenEnhancer()
                ,jwtAccessTokenConverter
                ,new PlatformSaveTokenEnhancer(userSessionTokenRepository)
        ));
        return tokenEnhancerChain;
    }

    /**
     * 令牌服务
     * @return
     */
    @Bean
    @Primary
    public AuthorizationServerTokenServices tokenService(@Autowired JwtConfig jwtConfig) {
        DefaultTokenServices tokenService = new DefaultTokenServices();
        tokenService.setClientDetailsService(clientDetailsService);
        tokenService.setSupportRefreshToken(true);
        tokenService.setTokenStore(tokenStore);
        tokenService.setTokenEnhancer(tokenEnhancerChain);
        tokenService.setAccessTokenValiditySeconds((int) jwtConfig.getAccessTokenValiditySeconds().getSeconds());
        tokenService.setRefreshTokenValiditySeconds((int) jwtConfig.getAccessTokenValiditySeconds().getSeconds());
        return tokenService;

    }

    /*** 3. 授权码服务 */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        return new RedisAuthorizationCodeServices();
    }
}
